'''
Created on 09.03.2011

@author: bstar
'''
import time
import json
import urllib
import logging
import traceback
from lxml import etree
from twisted.web.client import getPage
from twisted.internet.defer import Deferred
from dopplershift.collector.http import REQUEST_METHOD_GET, REQUEST_METHOD_POST
from dopplershift.collector.testing.tests import TestResult
from dopplershift.core.containers.mediator import getMediator

logger = logging.getLogger("CALL")
mediator = getMediator()

class CallTestItem:
    _auth_key = 'skdjfoerfmssdjfnskjdfns'
    def __init__(self, id, upstream, service, req_params, urls_match, cookies=None, auth=None, method=REQUEST_METHOD_GET, return_data=None, timeout=15, warn_delay=1, error_delay=5):
        self._id = id
        self._warn_delay = warn_delay
        self._error_delay = error_delay
        self._upstream = upstream
        self._service = service
        self._url = "%s/%s"%(self._upstream, self._service)
        self._method = REQUEST_METHOD_POST
        self._req_params = req_params
        self._urls_match = urls_match
        self._auth = auth
        self._cookies = cookies
        self._errors = 0
        self._warns = 0
        self._positiv = 0
        self._return_data = return_data
    def runTest(self):
        self._defer = Deferred()
        self.access()
        return self._defer
    def getUrl(self, url_params):
        call_url = self._url
        for param_key, param_value in url_params.iteritems():
            call_url= call_url.replace("{%s}"%param_key, param_value)
        return call_url
    def access(self):
        if not self._auth:
            return self._access()
        key = mediator.get("AuthTestId")
        data = mediator.get("AuthTest")
        backend = mediator.get("AuthBackend")
        if self._cookies == None:
            self._cookies = {}
        self._cookies[self._auth_key] = key
        d = backend.setAuth(key, data)
        d.addCallbacks(self._authcallback, self._authcallback)
    def _authcallback(self, reason):
        self._access()
    def _access(self):
        headers = None
        postdata =  urllib.urlencode(self._req_params)
        self._url = self.getUrl(self._urls_match)
        if self._method == REQUEST_METHOD_POST:
            headers={'Content-Type':'application/x-www-form-urlencoded'}
        else:
            self._url = "%s?%s"%(self._url, postdata)
            postdata = None
        self._start_time = time.time()
        getPage(
                str(self._url),
                method=self._method,
                timeout=15,
                postdata=postdata,
                headers=headers,
                cookies=self._cookies,
                ).addCallbacks(
                               callback=self._accessResponse,
                               errback=self._accessError
                               )
    def _accessResponse(self, data):
        try:
            etree.fromstring(data)
        except:
            self._errors += 1
            logger.error("%s return unexpected data '%s' with type '%s'"%(self._id, data, type(data)))

        if self._return_data != None and self._return_data != data:
            self._warns += 1
            logger.warning('''%s return uneq """%s""" with pattern """%s"""'''%(self._id, data, self._return_data))
        else:            
            self._positiv += 1
        self._timeTest()
        self._finish()
    def _timeTest(self):
        delay = time.time() - self._start_time
        if delay > self._error_delay:
            self._errors += 1
            logger.error("Slowpoke response: %s delay is %s"%(self._id, delay))
        elif delay > self._warn_delay:
            self._warns += 1
            logger.warning("Slow response: %s delay is %s"%(self._id, delay))
    def _finish(self):
        self._defer.callback(TestResult(
                                        self._positiv, 
                                        self._warns, 
                                        self._errors
                                        )
        )
    def _accessError(self, err):
        logger.error("%s %s"%(self._id, err))
        self._errors += 1
        self._finish()